package com.yu.mall.util;

import org.apache.commons.collections.MapUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.*;

public class ListSortUtil {

    public static enum SortMode {
        DESC, ASC
    }

    /**
     * @Desc 列表排序
     * @Param [targetList, sortField, sortMode]
     * @Return void
     **/
    public static void sort(List targetList, final String sortField, final SortMode sortMode) {
        Collections.sort(targetList, new Comparator() {
            @Override
            public int compare(Object obj1, Object obj2) {
                int retVal = 0;
                try {
                    Object robj1 = null;
                    Object robj2 = null;
                    if (obj1 instanceof Map && obj2 instanceof Map) {
                        robj1 = ((Map) obj1).get(sortField);
                        robj2 = ((Map) obj2).get(sortField);
                    } else if (obj1 instanceof String && obj2 instanceof String) {
                        robj1 = (String) obj1;
                        robj2 = (String) obj2;
                    } else if (obj1 instanceof Number && obj2 instanceof Number) {
                        robj1 = (Number) obj1;
                        robj2 = (Number) obj2;
                    } else if (obj1 instanceof java.util.Date && obj2 instanceof java.util.Date) {
                        robj1 = (java.util.Date) obj1;
                        robj2 = (java.util.Date) obj2;
                    } else {
                        // 首字母转大写
                        String newStr = sortField.substring(0, 1).toUpperCase() + sortField.replaceFirst("\\w", "");
                        String methodStr = "get" + newStr;
                        Method method1 = (obj1).getClass().getMethod(methodStr);
                        Method method2 = (obj2).getClass().getMethod(methodStr);
                        robj1 = method1.invoke(obj1);
                        robj2 = method2.invoke(obj2);
                    }
                    if (robj1 instanceof java.util.Date) {
                        java.util.Date begin = (java.util.Date) robj1;
                        java.util.Date end = (java.util.Date) robj2;
                        return getRetVal(sortMode, begin, end);
                    }
                    if (robj1 instanceof Number) {
                        return getRetVal(sortMode, (Number) robj1, (Number) robj2);
                    }
                    if (sortMode != null && SortMode.DESC.equals(sortMode)) {
                        retVal = robj2.toString().compareTo(robj1.toString()); // 倒序
                    } else {
                        retVal = robj1.toString().compareTo(robj2.toString()); // 正序
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return retVal;
            }
        });
    }

    /**
     * @Desc list转map(map < key, obj >)
     * @Param [list, fieldName]
     * @Return java.util.Map<K, T>
     **/
    public static <K, T> Map<K, T> listToMap(List<T> list, String fieldName) {
        String getMethodName = buildGetMethdName(fieldName);
        K obj = null;
        Map<K, T> resultMap = new HashMap<>();
        for (T bean : list) {
            try {
                if (bean instanceof Map) {
                    obj = (K) MapUtils.getObject((Map) bean, fieldName);
                } else {
                    obj = (K) ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(bean.getClass(), getMethodName), bean);
                }
                resultMap.put(obj, bean);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return resultMap;
    }

    /**
     * @Desc list转map(map < key, value >)
     * @Param [list, fieldName, valueName]
     * @Return java.util.Map<K, V>
     **/
    public static <K, V> Map<K, V> listToMap(List<?> list, String fieldName, String valueName) {
        String getFieldName = buildGetMethdName(fieldName);
        String getValueName = buildGetMethdName(valueName);
        K key = null;
        V val = null;
        Map<K, V> resultMap = new HashMap<>();
        for (Object bean : list) {
            try {
                if (bean instanceof Map) {
                    key = (K) MapUtils.getObject((Map) bean, fieldName);
                    val = (V) MapUtils.getObject((Map) bean, valueName);
                } else {
                    key = (K) ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(bean.getClass(), getFieldName), bean);
                    val = (V) ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(bean.getClass(), getValueName), bean);
                }
                resultMap.put(key, val);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return resultMap;
    }

    /**
     * @Desc list转map(根据fieldName分组)
     * @Param [list, fieldName]
     * @Return java.util.Map<K, java.util.List < T>>
     **/
    public static <K, T> Map<K, List<T>> groupList(List<T> list, String fieldName) {
        String getMethodName = buildGetMethdName(fieldName);
        K obj = null;
        Map<K, List<T>> resultMap = new HashMap<>();
        List<T> innerList = null;
        for (T bean : list) {
            try {
                if (bean instanceof Map) {
                    obj = (K) MapUtils.getObject((Map) bean, fieldName);
                } else {
                    obj = (K) ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(bean.getClass(), getMethodName), bean);
                }
                innerList = resultMap.get(obj);
                if (null == innerList) {
                    innerList = new ArrayList<>();
                }
                innerList.add(bean);
                resultMap.put(obj, innerList);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return resultMap;
    }

    /**
     * @Desc 从列表对象中获取每个对象fieldName的值
     * @Param [list, fieldName]
     * @Return java.util.List<K>
     **/
    public static <K, T> List<K> collectFieldValues(List<T> list, String fieldName) {
        String getMethodName = buildGetMethdName(fieldName);
        K obj = null;
        List<K> resultList = new ArrayList<>();
        for (T bean : list) {
            try {
                if (bean instanceof Map) {
                    obj = (K) MapUtils.getObject((Map) bean, fieldName);
                } else {
                    obj = (K) ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(bean.getClass(), getMethodName), bean);
                }
                resultList.add(obj);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return resultList;
    }

    /**
     * @Desc 从列表对象中获取每个对象fieldName的值(可忽略特定值)
     * @Param [list, fieldName, ignoreValue]
     * @Return java.util.List<K>
     **/
    public static <K, T> List<K> collectFieldValues(List<T> list, String fieldName, Object ignoreValue) {
        List<K> tmptList = collectFieldValues(list, fieldName);
        List<K> resultList = new ArrayList<>();
        for (K k : tmptList) {
            if (ignoreValue == null) {
                if (k != null) {
                    resultList.add(k);
                }
            } else {
                if (!ignoreValue.equals(k)) {
                    resultList.add(k);
                }
            }
        }
        return resultList;
    }

    private static String buildGetMethdName(String fieldName) {
        return "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, fieldName.length());
    }

    private static int getRetVal(SortMode sortMode, java.util.Date begin, java.util.Date end) {
        int result = 0;
        if (sortMode != null && SortMode.DESC.equals(sortMode)) {
            if (begin.getTime() == end.getTime()) {
                result = 0;
            } else {
                result = begin.after(end) ? -1 : 1;
            }

        } else {
            if (begin.getTime() == end.getTime()) {
                result = 0;
            } else {
                result = begin.after(end) ? 1 : -1;
            }
        }
        return result;
    }

    private static int getRetVal(SortMode sortMode, Number begin, Number end) {
        int result = 0;
        if (sortMode != null && SortMode.DESC.equals(sortMode)) {
            if (begin.doubleValue() == end.doubleValue()) {
                result = 0;
            } else {
                result = begin.doubleValue() > end.doubleValue() ? -1 : 1;
            }
        } else {
            if (begin.doubleValue() == end.doubleValue()) {
                result = 0;
            } else {
                result = begin.doubleValue() > end.doubleValue() ? 1 : -1;
            }
        }
        return result;
    }
}